package io.github.bigbird0101.yousishi.sql.print;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.LoaderClassPath;

import java.util.Objects;

/**
 * <p> OldMysqlAdapter </p>
 *
 * @author fupengpeng
 * @version 1.0
 * @date 2025/6/20 9:45
 */
public class OldMysqlAdapter extends AbstractPrintSql {
    private static final String METHOD_NAME_FILL_SEND_PACKET = "fillSendPacket";
    private static final String CLASS_NAME_PREPARED_STATEMENT = "com.mysql.jdbc.PreparedStatement";
    public static final String CLASS_NAME_BYTE_ARRAY_ARRAY = "byte[][]";
    public static final String CLASS_NAME_INPUT_STREAM_ARRAY = "java.io.InputStream[]";
    public static final String CLASS_NAME_BOOL_ARRAY = "boolean[]";
    public static final String CLASS_NAME_INT_ARRAY = "int[]";

    @Override
    public boolean match(String className) {
        boolean equals = CLASS_NAME_PREPARED_STATEMENT.equals(className) ||
                CLASS_NAME_PREPARED_STATEMENT.equals(className.replaceAll("/", "."));
        if (equals) {
            System.out.println("匹配到com.mysql.jdbc.PreparedStatement Agent的sql打印注入");
        }
        return equals;
    }

    @Override
    public byte[] doPrintSqlClass(ClassLoader classLoader, Boolean isFormatSql) {
        try {
            ClassPool classPool = ClassPool.getDefault();
            classPool.appendClassPath(new LoaderClassPath(classLoader));
            CtClass ctClass = classPool.get(CLASS_NAME_PREPARED_STATEMENT.replaceAll("/", "."));
            ctClass.addMethod(getPrintSqlMethod(ctClass));
            final CtMethod fillSendPacketCtMethod = ctClass.getDeclaredMethod(METHOD_NAME_FILL_SEND_PACKET,
                    classPool.get(new String[]{CLASS_NAME_BYTE_ARRAY_ARRAY, CLASS_NAME_INPUT_STREAM_ARRAY, CLASS_NAME_BOOL_ARRAY, CLASS_NAME_INT_ARRAY}));
            if (Objects.nonNull(fillSendPacketCtMethod)) {
                fillSendPacketCtMethod.insertBefore("{davaPrintSql(asSql()," + isFormatSql + ");}");
            }
            return ctClass.toBytecode();
        } catch (Exception exception) {
            System.err.println(exception);
            throw new RuntimeException(exception);
        }
    }
}
